/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package models;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import javax.persistence.Entity;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.ManyToOne;
import play.db.jpa.Model;

/**
 * 
 * @author Ousama
 */
@Entity
public class OrganizationLead extends Model {
	@ManyToOne
	public IdeaDeveloper ideaDeveloper;
	@ManyToMany
	@JoinTable(name = "OrganizationLead1")
	public List<Organization> manages = new ArrayList<Organization>();
	@ManyToMany
	@JoinTable(name = "OrganizationLead2")
	public List<Organization> createdOrgs = new ArrayList<Organization>();

	public void delete2() {
		// deleteing the managed organization entry for this leader and if he is
		// the creator thn setting the creator to be null
		for (int i = 0; i < manages.size(); i++) {
			manages.get(i).managers.remove(this);
			if (manages.get(i).creator.equals(this)) {
				manages.get(i).creator = null;
			}
			manages.get(i).save();
		}

		this.delete();
	}

	/**
	 * @author OUSAMA
	 * @param dev
	 *            the developer that will create the organizaitonLead for
	 * @return the OrganizationLead i just saved
	 */
	public static OrganizationLead create(IdeaDeveloper dev) {
		OrganizationLead lead = new OrganizationLead();
		lead.ideaDeveloper = dev;
		lead.save();
		
		Log log = new Log("^ is now an organization lead.");
		log.ids = dev.id + "";
		log.types = "developer";
		log.save();
		
		return lead;
		
	}

	/**
	 * allows the Organization Lead to Send invitation to any Idea Developer to
	 * join the Organization which leading
	 * 
	 * @author OmarKhaled
	 * @param organization
	 *            the organization which the user is invited to
	 * @param invitedUser
	 *            the user which the invitation is sent to
	 * @param typeOfRequest
	 *            the type of the invitation and its by default here
	 *            "JoinOrgFromOrgToDev" because the organization is sending the
	 *            invitation to the idea developer
	 * @return the Request sent from the organization to the invited user
	 */
	public static Request inviteIdeaDeveloperToOrganization(
			Organization organization, IdeaDeveloper invitedUser,
			String typeOfRequest) {
		typeOfRequest = "JoinOrgFromOrgToDev";
		return Request.RequestMe(organization, invitedUser, typeOfRequest);
	}

	/**
	 * allows the Organization Lead to Send invitation to any Idea Developer to
	 * join any Entity in Organization which leading
	 * 
	 * @author OmarKhaled
	 * @param entity
	 *            the entity which the user is invited to
	 * @param invitedUser
	 *            the user which the invitation is sent to
	 * @param typeOfRequest
	 *            the type of the invitation and its by default here
	 *            "JoinEntFromEntToDev" because the entity is sending the
	 *            invitation to the idea developer
	 * @return the Request sent from the entity to the invited user
	 */
	public static Request inviteIdeaDeveloperToEntity(Entities entity,
			IdeaDeveloper invitedUser, String typeOfRequest) {
		typeOfRequest = "JoinEntFromEntToDev";
		return Request.RequestMe(entity, invitedUser, typeOfRequest);
	}

	/**
	 * allows the Organization Lead to block any user from the organization
	 * after explaining the reason as a notification to all organizers
	 * 
	 * @author OmarKhaled
	 * @param organization
	 *            organization which the user will be banned from viewing
	 * @param lead
	 *            the organization lead performing the action
	 * @param userBlocked
	 *            user which will be blocked from using or viewing organization
	 * @param reason
	 *            entered text by the organization lead as a reason to block the
	 *            specified user
	 */
	public static void blockFromOrganization(Organization organization,
			OrganizationLead lead, IdeaDeveloper userBlocked, String reason) {
		blockHelper1(organization, userBlocked);
		blockHelper2(organization, userBlocked);
		blockHelper3(organization, userBlocked);
		notifiyOrganizers(organization, lead, reason);
	}

	/**
	 * helper for the method blockFromOrganization it adds the blocked user to
	 * the array of blocked users in the organization , its entities and topics
	 * 
	 * @author OmarKhaled
	 * @param organization
	 *            organization which the user will be banned from viewing
	 * @param userBlocked
	 *            user which will be blocked from using or viewing organization
	 */
	public static void blockHelper1(Organization organization,
			IdeaDeveloper userBlocked) {
		organization.blocked.add(userBlocked);
		userBlocked.blockedOrg.add(organization);
		for (Entities entity : userBlocked.joinedEnt) {
			if(organization.liesIn.contains(entity)){
				entity.blocked.add(userBlocked);
				userBlocked.blockedEnt.add(entity);
				for (Topic topic : userBlocked.joinedTop) {
					if(entity.topics.contains(topic)){
						topic.blocked.add(userBlocked);
						userBlocked.blockedTopic.add(topic);	
					}
				}
			}
		}
		for (Topic topic : userBlocked.joinedTop) {
			if(organization.topics.contains(topic)){
				topic.blocked.add(userBlocked);
				userBlocked.blockedTopic.add(topic);	
			}
		}
		
		Log log = new Log("^ is blocked from ^.");
		log.ids = userBlocked.id + "," + organization.id;
		log.types = "developer,organization";
		log.save();

	}

	/**
	 * helper for the method blockFromOrganization it removes user from the
	 * array of members in the organization , its entities and topics
	 * 
	 * @author OmarKhaled
	 * @param organization
	 *            organization which the user will be banned from viewing
	 * @param userBlocked
	 *            user which will be blocked from using or viewing organization
	 */
	public static void blockHelper2(Organization organization,
			IdeaDeveloper userBlocked) {

		organization.members.remove(userBlocked);
		for (Entities entity : organization.liesIn) {
			entity.members.remove(userBlocked);
			for (Topic topic : entity.topics) {
				topic.joined.remove(userBlocked);
			}
		}
		for (Topic topic : organization.topics) {
			topic.joined.remove(userBlocked);
		}
		
		Log log = new Log("^ is blocked from ^.");
		log.ids = userBlocked.id + "," + organization.id;
		log.types = "developer,organization";
		log.save();

	}

	/**
	 * helper for the method blockFromOrganization it adds the followed user to
	 * the array of followed in the organization , its entities and topics
	 * 
	 * @author OmarKhaled
	 * @param organization
	 *            organization which the user will be banned from viewing
	 * @param userBlocked
	 *            user which will be blocked from using or viewing organization
	 */
	public static void blockHelper3(Organization organization,
			IdeaDeveloper userBlocked) {
		organization.followed.remove(userBlocked);
		for (Entities entity : organization.liesIn) {
			entity.followed.remove(userBlocked);
			for (Topic topic : entity.topics) {
				topic.followed.remove(userBlocked);
			}
		}
		for (Topic topic : organization.topics) {
			topic.followed.remove(userBlocked);
		}
		
		Log log = new Log("^ is blocked from ^.");
		log.ids = userBlocked.id + "," + organization.id;
		log.types = "developer,organization";
		log.save();
	}

	/**
	 * allows the Organization Lead to unblock any user from the organization
	 * after explaining the reason as a notification to all organizers
	 * 
	 * @author OmarKhaled
	 * @param organization
	 *            organization which the user will be unbanned from viewing
	 * @param lead
	 *            the organization lead performing the action
	 * @param userUnBlocked
	 *            user which will be unblocked from using or viewing
	 *            organization
	 * @param reason
	 *            entered text by the organization lead as a reason to unblock
	 *            the specified user
	 */
	public static void unBlockFromOrganization(Organization organization,
			OrganizationLead lead, IdeaDeveloper userUnBlocked, String reason) {
		unBlockHelper1(organization, userUnBlocked);
		unBlockHelper2(organization, userUnBlocked);
		//unBlockHelper3(organization, userUnBlocked);
		notifiyOrganizers(organization, lead, reason);
	}

	/**
	 * helper for the method unBlockFromOrganization it removes the unblocked
	 * user from the array of blocked users in the organization , its entities
	 * and topics
	 * 
	 * @author OmarKhaled
	 * @param organization
	 *            organization which the user will be unbanned from viewing
	 * @param userUnBlocked
	 *            user which will be unblocked to use or view organization
	 */
	public static void unBlockHelper1(Organization organization,
			IdeaDeveloper userUnBlocked) {
		organization.blocked.remove(userUnBlocked);
		userUnBlocked.blockedOrg.remove(organization);
		for (Entities entity : organization.liesIn) {
			entity.blocked.remove(userUnBlocked);
			userUnBlocked.blockedEnt.remove(entity);
			for (Topic topic : entity.topics) {
				topic.blocked.remove(userUnBlocked);
				userUnBlocked.blockedTopic.remove(topic);
			}
		}
		for (Topic topic : organization.topics) {
			topic.blocked.remove(userUnBlocked);
			userUnBlocked.blockedTopic.remove(topic);
		}
		
		Log log = new Log("^ is un-blocked from ^.");
		log.ids = userUnBlocked.id + "," + organization.id;
		log.types = "developer,organization";
		log.save();
	}

	/**
	 * helper for the method unBlockFromOrganization it adds user to the array
	 * of members in the organization , its entities and topics
	 * 
	 * @author OmarKhaled
	 * @param organization
	 *            organization which the user will be unbanned from viewing
	 * @param userUnBlocked
	 *            user which will be unblocked to use or view organization
	 */
	public static void unBlockHelper2(Organization organization,
			IdeaDeveloper userUnBlocked) {

		organization.members.add(userUnBlocked);
		for (Entities entity : userUnBlocked.blockedEnt) {
			if(organization.liesIn.contains(entity))
			entity.members.add(userUnBlocked);
			for (Topic topic : userUnBlocked.blockedTopic) {
				if(entity.topics.contains(topic))
				topic.joined.add(userUnBlocked);
			}
		}
		for (Topic topic : userUnBlocked.blockedTopic) {
			if(organization.topics.contains(topic))
			topic.joined.add(userUnBlocked);
		}
		
		Log log = new Log("^ is un-blocked from ^.");
		log.ids = userUnBlocked.id + "," + organization.id;
		log.types = "developer,organization";
		log.save();

	}

	/**
	 * helper for the method unBlockFromOrganization it removes the followed
	 * user from the array of followed in the organization , its entities and
	 * topics
	 * 
	 * @author OmarKhaled
	 * @param organization
	 *            organization which the user will be unbanned from viewing
	 * @param userUnBlocked
	 *            user which will be unblocked to use or view organization
	 */
	public static void unBlockHelper3(Organization organization,
			IdeaDeveloper userUnBlocked) {
		organization.followed.add(userUnBlocked);
		for (Entities entity : organization.liesIn) {
			entity.followed.add(userUnBlocked);
			for (Topic topic : entity.topics) {
				topic.followed.add(userUnBlocked);
			}
		}
		for (Topic topic : organization.topics) {
			topic.followed.add(userUnBlocked);
		}
		
		Log log = new Log("^ is un-blocked from ^.");
		log.ids = userUnBlocked.id + "," + organization.id;
		log.types = "developer,organization";
		log.save();
	}

	/**
	 * sends notification to all organizers in the Organization of the reason
	 * why a user is blocked/unblocked
	 * 
	 * @author OmarKhaled
	 * @param organization
	 *            the organization in which the block/unblock takes place
	 * @param lead
	 *            the Organization Lead who blocks/unblocks the user and
	 *            notifies the users
	 * @param reason
	 *            the statement sent from the lead to the organizers as a reason
	 *            of the action
	 */
	public static void notifiyOrganizers(Organization organization,
			OrganizationLead lead, String reason) {
		for (Entities entity : organization.liesIn) {
			for (Organizer organizer : entity.managers) {
				Notification.notify(reason, organizer.ideaDeveloper,
						lead.ideaDeveloper, new Date());
			}
			for (Topic topic : organization.topics) {
				for (Organizer organizer : topic.managers) {
					Notification.notify(reason, organizer.ideaDeveloper,
							lead.ideaDeveloper, new Date());
				}
			}
		}

		for (Topic topic : organization.topics) {
			for (Organizer organizer : topic.managers) {
				Notification.notify(reason, organizer.ideaDeveloper,
						lead.ideaDeveloper, new Date());
			}
		}
	}

	/**
	 * makes an organizer an organization lead
	 * 
	 * @author Omar el alfy
	 * @param leadOn
	 *            organization that the organizer becomes leader on leader on
	 * @param makeLead
	 *            organizer to be leader
	 * @return false if organizer is already a leader on this organization
	 */
	public static boolean makeOrganizationLead(Organization leadOn,
			Organizer makeLead) {
		try {
			List<OrganizationLead> listOfOrgLeads = new ArrayList<OrganizationLead>();
			listOfOrgLeads = leadOn.managers;
			for (int i = 0; i < listOfOrgLeads.size(); i++) {
				if (listOfOrgLeads.get(i).ideaDeveloper.username
						.equals(makeLead.ideaDeveloper.username))
					return false;
			}
			OrganizationLead lead = null;
			if (OrganizationLead.count("ideaDeveloper=?",
					makeLead.ideaDeveloper) == 0) {
				lead = new OrganizationLead();
				lead.ideaDeveloper = makeLead.ideaDeveloper;
			} else {
				lead = OrganizationLead.find("ideaDeveloper=?",
						makeLead.ideaDeveloper).first();
			}
			lead.manages.add(leadOn);
			lead.save();
			leadOn.managers.add(lead);
			leadOn.save();
			
			Log log = new Log("^ is now the lead of ^.");
			log.ids = makeLead.id + "," + leadOn.id;
			log.types = "developer,organization";
			log.save();
			
			return true;
		} catch (Exception e) {
			return false;
		}
	}

	/**
	 * restricts an organizer to a entity by removing this organizer from
	 * organizing any other entity or topic
	 * @author Omar el alfy
	 * @param Restricted
	 *            organizer to be restricted
	 * @param entityRestrictTo
	 *            entity to be restricted on
	 * @return returns a string containing a list of entities and topics removed from and entities and topics cannot be removed from 
	 */
	public static String restrictAccessEntity(Organizer Restricted,
			Entities entityRestrictTo) {
		List<Entities> listOfEntitiesManaged = new ArrayList<Entities>();
		List<Topic> listOfTopicsManaged = new ArrayList<Topic>();
		String listOfEntities = "Entities  : ";
		String listOfTopics = "Topics : ";
		String notRemovedEntities = "Entities :";
		String notRemovedTopics = "Topics :";
		listOfEntitiesManaged = Restricted.manages;
		listOfTopicsManaged = Restricted.managedTopics;
		for (int i = 0; i < listOfEntitiesManaged.size(); i++) {
			Entities entity = listOfEntitiesManaged.get(i);
			if (entityRestrictTo.liesIn.name.equals(entity.liesIn.name)) {
				if (entity.managers.size() > 1) {
					if(entity.name.equals(entityRestrictTo.name))
					listOfEntities += entity.name + " , ";
					entity.managers.remove(Restricted);
					Restricted.manages.remove(entity);
					entity.save();
					i--;
				} else
					notRemovedEntities += entity.name + " , ";
			}
		}
		for (int i = 0; i < listOfTopicsManaged.size(); i++) {
			Topic topic = listOfTopicsManaged.get(i);
			if (entityRestrictTo.liesIn.equals(topic.topicOrg)) {
				if (topic.managers.size() > 1) {
					listOfTopics += topic.title + " , ";
					topic.managers.remove(Restricted);
					Restricted.managedTopics.remove(topic);
					topic.save();
				} else
					notRemovedTopics += topic.title + " , ";
			}
		}
		if (!entityRestrictTo.managers.contains(Restricted)) {
			entityRestrictTo.managers.add(Restricted);
			entityRestrictTo.save();
			Restricted.manages.add(entityRestrictTo);
			Restricted.save();
		}

		
		Log log = new Log("^ is restricted to ^.");
		log.ids = Restricted.id + "," + entityRestrictTo.id;
		log.types = "organizer,entity";
		log.save();
		
		return listOfEntities + "&" + listOfTopics + "%^%" + notRemovedEntities
				+ "&" + notRemovedTopics;

	}

	/**
	 * restricts an organizer to a topic by removing this organizer from
	 * organizing any other entity or topic
	 * 
	 * @author Omar el alfy
	 * @param Restricted
	 *            organizer to be restricted
	 * @param topicRestrictTo
	 *            topic to be restricted on
	 * @return returns a string containing a list of entities and topics removed from and entities and topics cannot be removed from
	 */
	public static String restrictAccessTopic(Organizer Restricted,
			Topic topicRestrictTo) {

		Organization organization = new Organization();
		try {
			if (!topicRestrictTo.topicOrg.equals(null)) {
				organization = topicRestrictTo.topicOrg;

			}
		} catch (Exception E) {
			if (!topicRestrictTo.topicEnt.equals(null)) {
				Entities e = topicRestrictTo.topicEnt;
				organization = e.liesIn;

			}
		}
		String notRemovedEntities = "Entities : ";
		String notRemovedTopics = "Topics : ";
		String listOfEntities = "Entities  :";
		String listOfTopics = "Topics :";
		List<Entities> listOfEntitiesManaged = new ArrayList<Entities>();
		List<Topic> listOdTopicsManaged = new ArrayList<Topic>();
		listOfEntitiesManaged = Restricted.manages;
		listOdTopicsManaged = Restricted.managedTopics;
		for (int i = 0; i < listOfEntitiesManaged.size(); i++) {
			Entities entity = listOfEntitiesManaged.get(i);
			if (entity.liesIn.name.equals(organization.name)) {
				if (entity.managers.size() > 1) {
					listOfEntities += entity.name + " , ";
					entity.managers.remove(Restricted);
					Restricted.manages.remove(entity);
					entity.save();
					i--;
				} else
					notRemovedEntities += entity.name + " , ";
			}
		}
		for (int i = 0; i < listOdTopicsManaged.size(); i++) {
			Topic topic = listOdTopicsManaged.get(i);
			if (organization.equals(topic.topicOrg)) {
				if (topic.managers.size() > 1) {
					if(topic.title.equals(topicRestrictTo.title))
					listOfTopics += topic.title + " , ";
					topic.managers.remove(Restricted);
					Restricted.managedTopics.remove(topic);
					topic.save();
				} else
					notRemovedTopics += topic.title + " , ";
			}
		}
		if (!topicRestrictTo.managers.contains(Restricted)) {
			topicRestrictTo.managers.add(Restricted);
			topicRestrictTo.save();
			Restricted.managedTopics.add(topicRestrictTo);
			Restricted.save();
		}
		
		Log log = new Log("^ is restricted to ^.");
		log.ids = Restricted.id + "," + topicRestrictTo.id;
		log.types = "organizer,topic";
		log.save();
		
		return listOfEntities + "&" + listOfTopics + "%^%" + notRemovedEntities
				+ "&" + notRemovedTopics;


	}

	public String toString() {

		return this.ideaDeveloper.username;
	}

}
